import pytest
from common.request_util_test import RequestUtil
from common.test_yaml_util_test import YamlUtil
from config import datas
from datetime import datetime, timedelta
import time


class TestMonitoringDashboard:
    flag_monitoring_dashboard_installed_stat = 0  # flag置0表示monitoring-dashboard之前未安装，需要在本测试套临时安装。置1表示之前已安装，无需安装
    dashboardID = ''  # 格式类似 "2025-03-03-07-47-14-3c1b9dd5-7cd0-43de-a038-badb8a5574b5"
    widgetID = ''  # 格式类似 "2025-03-04-06-47-01-e16b6fc9-20c3-4804-8860-d085e267b2cd"
    instances = []  # 存储监控实例。监控指标在datas.py中由用户配置

    @pytest.mark.parametrize('yaml',
                             YamlUtil().read_testcase_yaml('v24.09/monitoringDashboard/POST_create_dashboard.yaml'))
    def test_create_dashboard(self, yaml):
        # 创建单个Dashboard资源
        # 首先检查当前是否已安装monitoring-dashboard扩展组件，如果未安装，则先安装。然后在最后一个用例处卸载。
        uri_installed_ext = "/clusters/host/rest/application-management/v1beta1/helm-releases?extension=true"
        url_installed_ext = datas.baseUrl + uri_installed_ext
        method_installed_ext = "GET"
        headers_installed_ext = {"Content-Type": "application/json"}
        req_installed_ext = RequestUtil().send_request(method_installed_ext, url_installed_ext,
                                                       headers=headers_installed_ext)
        req_installed_ext = req_installed_ext.json()  # 将返回信息读取为json格式。如果是content()则会读取为bytes类型数据
        for i in req_installed_ext["data"]["items"]:
            if i["name"] == "monitoring-dashboard":
                TestMonitoringDashboard.flag_monitoring_dashboard_installed_stat = 1
                # print("检测到当前已安装monitoring-dashboard扩展组件，使用当前扩展组件进行测试，测试结束后不卸载该扩展组件")
                break
            else:
                continue
        if TestMonitoringDashboard.flag_monitoring_dashboard_installed_stat == 0:
            # print("检测到当前未安装monitoring-dashboard扩展组件，现开始安装，并在测试结束后卸载")
            uri_dashboard_install = "/rest/application-management/v1beta1/helm-releases/namespace/{namespace}/release/{release}"
            uri_dashboard_install = uri_dashboard_install.replace("{namespace}",
                                                                  datas.test_monitoring_dashboard["namespace"])
            uri_dashboard_install = uri_dashboard_install.replace("{release}",
                                                                  datas.test_monitoring_dashboard["release"])
            uri_dashboard_install = datas.baseUrl + uri_dashboard_install
            method_dashboard_install = "POST"
            headers_dashboard_install = {"Content-Type": "application/json"}
            data_dashboard_install = {
                "chartName": datas.test_monitoring_dashboard["release"],
                "repoName": datas.test_monitoring_dashboard["repoName"],
                "version": datas.test_monitoring_dashboard["version"],
                "values": datas.test_monitoring_dashboard["values"],
            }
            req_dashboard_install = RequestUtil().send_request(method_dashboard_install, uri_dashboard_install,
                                                               headers=headers_dashboard_install,
                                                               json=data_dashboard_install)
            assert req_dashboard_install.status_code == 202
            # 通过while语句轮询检测monitoring-dashboard扩展组件是否安装成功。
            flag_time = 0  # 防止死循环
            url_try = datas.baseUrl + "/clusters/host/rest/monitoring-dashboard/v1beta1/dashboards"
            while 1:
                req_try = RequestUtil().send_request("GET", url_try)
                if str(abs(req_try.status_code))[0] == "5":  # 即5xx状态码
                    # if req_try.status_code == 502 or req_try.status_code == 503:
                    time.sleep(2)
                    flag_time += 2
                    if flag_time >= 120:  # 最多等待2min，防止死循环
                        print(
                            "ERR: monitoring-dashboard扩展组件在2min仍未安装完毕，请手动排查网络状态，或手动安装扩展组件")
                        break
                    continue
                elif req_try.status_code == 200:
                    # print("monitoring-dashboard扩展组件安装成功。共耗时:", flag_time, "秒")
                    break
                else:
                    print("ERR: 出现预期之外的状态码:", req_try.status_code, "请手工排查")
        # 创建单个Dashboard资源
        uri = yaml['request']['url']
        url = datas.baseUrl + uri
        method = yaml['request']['method']
        headers = yaml['request']['headers']
        data = yaml['request']['data']
        data["displayName"] = datas.test_monitoring_dashboard["dashboard_name"]
        data["creator"] = datas.test_monitoring_dashboard["dashboard_creator"]
        req = RequestUtil().send_request(method, url, headers=headers, json=data)
        assert req.status_code == yaml['validate'][0]['equals']['status_code']

    @pytest.mark.parametrize('yaml',
                             YamlUtil().read_testcase_yaml('v24.09/monitoringDashboard/GET_get_dashboard_list.yaml'))
    def test_get_dashboard_list(self, yaml):
        # 获取Dashboard列表
        uri = yaml['request']['url']
        url = datas.baseUrl + uri
        method = yaml['request']['method']
        headers = yaml['request']['headers']
        data = yaml['request']['data']
        req = RequestUtil().send_request(method, url, headers=headers, json=data)
        assert req.status_code == yaml['validate'][0]['equals']['status_code']
        # 写入公用变量TestMonitoringDashboard.dashboardID
        req_json = req.json()
        for i in req_json["data"]:
            if i["displayName"] == datas.test_monitoring_dashboard["dashboard_name"]:
                TestMonitoringDashboard.dashboardID = i["dashboardID"]
                assert TestMonitoringDashboard.dashboardID
                break
        if TestMonitoringDashboard.dashboardID == '':
            print("error，未获取到上一步创建的dashboard！")

    @pytest.mark.parametrize('yaml', YamlUtil().read_testcase_yaml(
        'v24.09/monitoringDashboard/GET_get_specified_dashboard.yaml'))
    def test_get_specified_dashboard(self, yaml):
        # 获取单个Dashboard资源
        uri = yaml['request']['url']
        uri = uri.replace("{dashboardID}", TestMonitoringDashboard.dashboardID)
        uri = uri.replace("{step}", datas.test_monitoring_dashboard["step"])  # step=2表示每2秒取一次数据
        # 计算end_time和start_time
        end_time = datetime.utcnow().isoformat(timespec='seconds') + 'Z'  # 输出格式 "2025-03-03T08:59:49Z"
        end_time_format = datetime.fromisoformat(end_time.replace('Z', '+00:00'))  # 转化格式，方便下一步计算x分钟前
        end_time_10min_ago = end_time_format - timedelta(minutes=datas.test_monitoring_dashboard["time_resent"])
        start_time = end_time_10min_ago.isoformat(timespec='seconds').replace('+00:00', 'Z')
        uri = uri.replace("{end_time}", end_time)
        uri = uri.replace("{start_time}", start_time)
        url = datas.baseUrl + uri
        method = yaml['request']['method']
        headers = yaml['request']['headers']
        data = yaml['request']['data']
        req = RequestUtil().send_request(method, url, headers=headers, json=data)
        assert req.status_code == yaml['validate'][0]['equals']['status_code']

    @pytest.mark.parametrize('yaml', YamlUtil().read_testcase_yaml(
        'v24.09/monitoringDashboard/PATCH_modify_specified_dashboard.yaml'))
    def test_modify_specified_dashboard(self, yaml):
        # 修改单个Dashboard资源（修改dashboard名称）
        uri = yaml['request']['url']
        uri = uri.replace("{dashboardID}", TestMonitoringDashboard.dashboardID)
        url = datas.baseUrl + uri
        method = yaml['request']['method']
        headers = yaml['request']['headers']
        data = yaml['request']['data']
        data["displayName"] = datas.test_monitoring_dashboard["dashboard_name_modified"]
        req = RequestUtil().send_request(method, url, headers=headers, json=data)
        assert req.status_code == yaml['validate'][0]['equals']['status_code']
        # 健壮性增强：还原修改内容，以便单独执行用例时不报错（修改内容相同会报错）
        data2 = data
        data2["displayName"] = datas.test_monitoring_dashboard["dashboard_name"]
        req2 = RequestUtil().send_request(method, url, headers=headers, json=data2)
        assert req2.status_code == yaml['validate'][0]['equals']['status_code']

    @pytest.mark.parametrize('yaml',
                             YamlUtil().read_testcase_yaml('v24.09/monitoringDashboard/GET_get_indicator_list.yaml'))
    def test_get_indicator_list(self, yaml):
        # 获取指标名称列表
        uri = yaml['request']['url']
        uri = uri.replace("{data_source}", datas.test_monitoring_dashboard["data_source"])
        url = datas.baseUrl + uri
        method = yaml['request']['method']
        headers = yaml['request']['headers']
        data = yaml['request']['data']
        req = RequestUtil().send_request(method, url, headers=headers, json=data)
        assert req.status_code == yaml['validate'][0]['equals']['status_code']

    @pytest.mark.parametrize('yaml', YamlUtil().read_testcase_yaml(
        'v24.09/monitoringDashboard/GET_get_instance_list_by_indicator.yaml'))
    def test_get_instance_list_by_indicator(self, yaml):
        # 根据指标名称获取实例列表
        uri = yaml['request']['url']
        uri = uri.replace("{indicator_name}", datas.test_monitoring_dashboard["indicator_name"])
        uri = uri.replace("{data_source}", datas.test_monitoring_dashboard["data_source"])
        url = datas.baseUrl + uri
        method = yaml['request']['method']
        headers = yaml['request']['headers']
        data = yaml['request']['data']
        req = RequestUtil().send_request(method, url, headers=headers, json=data)
        assert req.status_code == yaml['validate'][0]['equals']['status_code']
        # 将实例列表的前2条数据写入TestMonitoringDashboard.instances，以便后续用例使用
        req_json = req.json()
        # req_json["data"]["instances"][0]["metric"]本身为dict格式，需要转为str，并将'替换为"。不然后续无法反序列化为json
        tmp_instances0 = str(req_json["data"]["instances"][0]["metric"]).replace("\'", "\"")
        tmp_instances1 = str(req_json["data"]["instances"][1]["metric"]).replace("\'", "\"")
        if req_json["data"]["instances"][0]["metric"]:
            TestMonitoringDashboard.instances.append(tmp_instances0)
        if req_json["data"]["instances"][1]["metric"]:
            TestMonitoringDashboard.instances.append(tmp_instances1)
        assert TestMonitoringDashboard.instances

    @pytest.mark.parametrize('yaml', YamlUtil().read_testcase_yaml(
        'v24.09/monitoringDashboard/GET_get_instance_data_by_instance_list.yaml'))
    def test_get_instance_data_by_instance_list(self, yaml):
        # 获取实例列表中每个实例的数据
        uri = yaml['request']['url']
        uri = uri.replace("{data_source}", datas.test_monitoring_dashboard["data_source"])
        uri = uri.replace("{step}", datas.test_monitoring_dashboard["step"])
        # 处理end_time和start_time
        end_time = datetime.utcnow().isoformat(timespec='seconds') + 'Z'  # 输出格式 "2025-03-03T08:59:49Z"
        end_time_format = datetime.fromisoformat(end_time.replace('Z', '+00:00'))  # 转化格式，方便下一步计算x分钟前
        end_time_10min_ago = end_time_format - timedelta(minutes=datas.test_monitoring_dashboard["time_resent"])
        start_time = end_time_10min_ago.isoformat(timespec='seconds').replace('+00:00', 'Z')
        uri = uri.replace("{end_time}", end_time)
        uri = uri.replace("{start_time}", start_time)
        url = datas.baseUrl + uri
        method = yaml['request']['method']
        headers = yaml['request']['headers']
        data = yaml['request']['data']
        data = TestMonitoringDashboard.instances
        req = RequestUtil().send_request(method, url, headers=headers, json=data)
        assert req.status_code == yaml['validate'][0]['equals']['status_code']

    @pytest.mark.parametrize('yaml',
                             YamlUtil().read_testcase_yaml('v24.09/monitoringDashboard/POST_create_widget.yaml'))
    def test_create_widget(self, yaml):
        # 创建单个Widget资源（创建widget时名称可以相同。但是widgetID不能相同，不然会报错）
        uri = yaml['request']['url']
        url = datas.baseUrl + uri
        method = yaml['request']['method']
        headers = yaml['request']['headers']
        data = yaml['request']['data']
        data["dashboardID"] = TestMonitoringDashboard.dashboardID
        data["dataSource"] = datas.test_monitoring_dashboard["data_source"]
        data["displayName"] = datas.test_monitoring_dashboard["widget_name"]
        data["instances"] = TestMonitoringDashboard.instances
        req = RequestUtil().send_request(method, url, headers=headers, json=data)
        assert req.status_code == yaml['validate'][0]['equals']['status_code']
        # 创建成功后，直接获取widgetID，并写入TestMonitoringDashboard.widgetID
        req_json = req.json()
        TestMonitoringDashboard.widgetID = req_json["data"]["spec"]["widgetID"]
        assert TestMonitoringDashboard.widgetID

    @pytest.mark.parametrize('yaml', YamlUtil().read_testcase_yaml(
        'v24.09/monitoringDashboard/PATCH_modify_specified_widget.yaml'))
    def test_modify_specified_widget(self, yaml):
        # 修改单个Widget资源
        uri = yaml['request']['url']
        uri = uri.replace("{widgetID}", TestMonitoringDashboard.widgetID)
        url = datas.baseUrl + uri
        method = yaml['request']['method']
        headers = yaml['request']['headers']
        data = yaml['request']['data']
        data["dashboardID"] = TestMonitoringDashboard.dashboardID
        data["dataSource"] = datas.test_monitoring_dashboard["data_source"]
        data["displayName"] = datas.test_monitoring_dashboard["widget_name_modified"]
        req = RequestUtil().send_request(method, url, headers=headers, json=data)
        assert req.status_code == yaml['validate'][0]['equals']['status_code']

    @pytest.mark.parametrize('yaml', YamlUtil().read_testcase_yaml(
        'v24.09/monitoringDashboard/DELETE_delete_specified_widget.yaml'))
    def test_delete_specified_widget(self, yaml):
        # 删除单个Widget资源
        uri = yaml['request']['url']
        uri = uri.replace("{widgetID}", TestMonitoringDashboard.widgetID)
        url = datas.baseUrl + uri
        method = yaml['request']['method']
        headers = yaml['request']['headers']
        data = yaml['request']['data']
        req = RequestUtil().send_request(method, url, headers=headers, json=data)
        assert req.status_code == yaml['validate'][0]['equals']['status_code']

    @pytest.mark.parametrize('yaml', YamlUtil().read_testcase_yaml(
        'v24.09/monitoringDashboard/DELETE_delete_specified_dashboard.yaml'))
    def test_delete_specified_dashboard(self, yaml):
        # 删除单个Dashboard资源
        uri = yaml['request']['url']
        uri = uri.replace("{dashboardID}", TestMonitoringDashboard.dashboardID)
        url = datas.baseUrl + uri
        method = yaml['request']['method']
        headers = yaml['request']['headers']
        data = yaml['request']['data']
        req = RequestUtil().send_request(method, url, headers=headers, json=data)
        assert req.status_code == yaml['validate'][0]['equals']['status_code']
        # 在最后一个用例处删除第1个用例安装的monitoring-dashboard扩展组件
        if TestMonitoringDashboard.flag_monitoring_dashboard_installed_stat == 0:
            # flag置0表示monitoring-dashboard之前未安装，需要在本测试套临时安装并卸载
            uri_dashboard_delete = ("/clusters/host/rest/application-management/v1beta1/"
                                    "helm-releases/namespace/{namespace}/release/{release}")
            uri_dashboard_delete = uri_dashboard_delete.replace("{namespace}",
                                                                datas.test_monitoring_dashboard["namespace"])
            uri_dashboard_delete = uri_dashboard_delete.replace("{release}", datas.test_monitoring_dashboard["release"])
            url_dashboard_delete = datas.baseUrl + uri_dashboard_delete
            method_dashboard_delete = "DELETE"
            headers_dashboard_delete = {"Content-Type": "application/json"}
            req_dashboard_delete = RequestUtil().send_request(method_dashboard_delete, url_dashboard_delete,
                                                              headers=headers_dashboard_delete)
            assert req_dashboard_delete.status_code == 200
            # 轮询monitoring-dashboard接口，如果接口返回5xx，则说明卸载完全结束
            flag_time = 0  # 防止死循环
            url_try = datas.baseUrl + "/clusters/host/rest/monitoring-dashboard/v1beta1/dashboards"
            while 1:
                req_try = RequestUtil().send_request("GET", url_try)
                if req_try.status_code == 200:
                    time.sleep(1)
                    flag_time += 1
                    if flag_time >= 30:
                        print("ERR: monitoring-dashboard扩展组件在30s仍未卸载完毕，请手动排查并卸载")
                        break
                    continue
                elif req_try.status_code == 404:
                    # print("monitoring-dashboard扩展组件卸载成功。共耗时:", flag_time, "秒")
                    break
                else:
                    print("ERR: 出现预期之外的状态码:", req_try.status_code, "请手工排查")
            time.sleep(20)  # 必须预留充足的时间等待helm卸载完毕
